#include <alsa/asoundlib.h>  //ALSA头文件
#include <opus/opus.h> // Opus头文件
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>

// 录音器结构体
struct recorder {
    snd_pcm_t* device;     // ALSA PCM设备句柄
    int channels;          // 音频通道数
    int sample_rate;       // 采样率
    int duration;          // 音频帧持续时间(毫秒)
    int frames;            // 每个音频帧的采样点数
    OpusEncoder* encoder;  // Opus编码器
    opus_int16* buffer;    // 音频数据缓冲区
};

/**
 * 创建录音器实例
 * @param name        ALSA设备名称，通常为"default"
 * @param sample_rate 采样率
 * @param channels    通道数
 * @param duration    每帧持续时间(毫秒)
 * @return 录音器实例指针，失败返回NULL
 */
struct recorder* recorder_create(const char* name, int sample_rate, int channels, int duration)
{
    struct recorder* recorder = malloc(sizeof(struct recorder));
    if (!recorder)
    {
        return NULL;
    }

    recorder->channels = channels;
    recorder->sample_rate = sample_rate;
    recorder->duration = duration;

    // 打开ALSA录音设备
    int error = snd_pcm_open(&recorder->device, name, SND_PCM_STREAM_CAPTURE, 0);
    if (error < 0)
    {
        fprintf(stderr, "open %s failed: %s\n", name, snd_strerror(error));
        free(recorder);
        return NULL;
    }

    // 设置PCM设备参数
    error = snd_pcm_set_params(recorder->device,
                            SND_PCM_FORMAT_S16_LE,
                            SND_PCM_ACCESS_RW_INTERLEAVED,
                            recorder->channels,
                            recorder->sample_rate,
                            1,
                            recorder->duration * 1000);
    if (error < 0) {
        fprintf(stderr, "snd_pcm_set_params: %s\n", snd_strerror(error));
        snd_pcm_close(recorder->device);
        free(recorder);
        return NULL;
    }

    // 创建Opus编码器
    recorder->encoder = opus_encoder_create(recorder->sample_rate, recorder->channels, OPUS_APPLICATION_AUDIO, &error);
    if (error != OPUS_OK) {
        fprintf(stderr, "opus_encoder_create: %s\n", opus_strerror(error));
        snd_pcm_close(recorder->device);
        free(recorder);
        return NULL;
    }

    // 计算每帧的采样点数并分配缓冲区
    recorder->frames = recorder->sample_rate * recorder->duration / 1000;
    recorder->buffer = malloc(snd_pcm_frames_to_bytes(recorder->device, recorder->frames));
    if (!recorder->buffer) {
        opus_encoder_destroy(recorder->encoder);
        snd_pcm_close(recorder->device);
        free(recorder);
        return NULL;
    }

    return recorder;
}

/**
 * 销毁录音器实例并释放资源
 * @param recorder 录音器实例
 */
void recorder_destroy(struct recorder *recorder)
{
    if (recorder) {
        if (recorder->buffer) {
            free(recorder->buffer);
            recorder->buffer = NULL;
        }
        if (recorder->device) {
            snd_pcm_close(recorder->device);
            recorder->device = NULL;
        }
        if (recorder->encoder) {
            opus_encoder_destroy(recorder->encoder);
            recorder->encoder = NULL;
        }
        free(recorder);
    }
}

/**
 * 启动录音
 * @param recorder 录音器实例
 * @return 成功返回0，失败返回负值
 */
int recorder_start(struct recorder *recorder)
{
    if (!recorder)
    {
        return -1;
    }

    return snd_pcm_start(recorder->device);
}

/**
 * 停止录音
 * @param recorder 录音器实例
 * @return 成功返回0，失败返回负值
 */
int recorder_stop(struct recorder *recorder)
{
    if (!recorder)
    {
        return -1;
    }

    return snd_pcm_drain(recorder->device);
}

/**
 * 录制音频并进行Opus编码
 * @param recorder 录音器实例
 * @param data 用于存储编码后数据的缓冲区
 * @param size 缓冲区大小
 * @return 编码后的字节数，失败返回负值
 */
int32_t record_audio(struct recorder* recorder, char* data, size_t size)
{
    if (!recorder)
    {
        return -1;
    }

    // 从PCM设备读取音频数据
    snd_pcm_sframes_t frames = snd_pcm_readi(recorder->device, recorder->buffer, recorder->frames);
    if (frames < 0) {
        fprintf(stderr, "snd_pcm_readi: %s\n", snd_strerror(frames));
        return -1;
    }
    
    // 使用Opus编码器编码音频数据
    opus_int32 enc_bytes = opus_encode(recorder->encoder, recorder->buffer, frames, data, size);
    if (enc_bytes < 0)
    {
        fprintf(stderr, "opus_encode: %s\n", opus_strerror(enc_bytes));
        return -1;
    }

    return enc_bytes;
}

// 发送数据的缓冲区
char buffer[4096];

int main()
{
    // 创建UDP套接字
    int sk = socket(AF_INET, SOCK_DGRAM, 0);
    if (sk < 0)
    {
        perror("socket");
        return EXIT_FAILURE;
    }

    // 设置目标地址（客户端程序）
    struct sockaddr_in server_addr;
    memset(&server_addr, 0, sizeof(server_addr));
    // 配置服务器地址信息
    server_addr.sin_family = AF_INET; // IPv4
    server_addr.sin_port = htons(8888);
    server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");

    // 创建录音器实例，采样率16000Hz，单声道，帧时长60ms
    struct recorder* recorder = recorder_create("default", 16000, 1, 60);
    if (!recorder)
    {
        return EXIT_FAILURE;
    }

    //开始录音
    recorder_start(recorder);

    // 主循环：录制并发送音频数据
    while(1)
    {
        // 录制一帧音频并编码
        int32_t bytes = record_audio(recorder, buffer, sizeof(buffer));
        if (bytes < 0)
        {
            break;
        }

        // 将编码后的音频数据发送到客户端程序
        ssize_t txbytes = sendto(sk, buffer, bytes, 0,
                             (const struct sockaddr *)&server_addr, sizeof(server_addr));
        if (txbytes != bytes) {
            perror("sendto");
            continue;
        }

        printf("send %d bytes\n", txbytes);
    }

    // 停止录音并清理资源
    recorder_stop(recorder);
    recorder_destroy(recorder);
    close(sk);

    return EXIT_SUCCESS;
}
